from typing import Optional

from tortoise.expressions import Q

from app.core.crud import CRUDBase
from app.models.admin import Menu, User, Role, MenuType
from app.schemas.menus import MenuCreate, MenuUpdate, VbenMenu


class MenuController(CRUDBase[Menu, MenuCreate, MenuUpdate]):
    def __init__(self):
        super().__init__(model=Menu)

    async def get_by_menu_path(self, path: str) -> Optional["Menu"]:
        return await self.model.filter(path=path).first()

    async def get_menu(self, user_id):
        """根据用户id获取菜单权限"""
        user_obj = await User.filter(id=user_id).first() if user_id else None
        menus: list[Menu] = []
        if not user_id or user_obj.is_superuser:
            menus = await Menu.all()
        else:
            role_objs: list[Role] = await user_obj.roles
            for role_obj in role_objs:
                menu = await role_obj.menus
                menus.extend(menu)
            menus = list(set(menus))

        # 根据order排序
        menus = sorted(menus, key=lambda x: x.order)
        return menus


    async def find_by_role_id(self, role_id) -> list[Menu]:
        """根据角色id获取菜单权限"""
        role = await Role.get(id=role_id)
        return await role.menus


    async def get_vben_menu(self, user_id, filter_button=True):
        """根据用户id获取菜单权限"""
        menus = await self.get_menu(user_id)

        # 转换成vben-admin需要的VbenMenu格式
        menus = [VbenMenu.menu_to_vben(menu).model_dump() for menu in menus]
        # 过滤按钮类型
        if filter_button:
            menus = list(filter(lambda x: x["menuType"] != MenuType.BUTTON, menus))

        menus_dict = {menu["id"]: menu for menu in menus}

        # 转换成菜单树形结构
        for menu in menus:
            if menu["parentId"] and menu["parentId"] in menus_dict:
                menus_dict[menu["parentId"]]["children"].append(menu)

        return list(filter(lambda x: x["parentId"] == 0, menus))

    async def tree_list(self, code, name):
        """
        获取菜单树
        """
        q = Q()
        if code:
            q &= Q(code__contains=code)
        if name:
            q &= Q(name__contains=name)
        menu_list = await self.model.filter(q).order_by("order", "id")
        menu_list = [await menu.to_dict() for menu in menu_list]

        # 搜索时不返回树形结构
        if code or name:
            return menu_list

        # 转换成树形结构
        menu_dict = {menu["id"]: menu for menu in menu_list}
        for menu in menu_list:
            if menu["parent_id"] and menu["parent_id"] in menu_dict:
                if "children" not in menu_dict[menu["parent_id"]]:
                    menu_dict[menu["parent_id"]]["children"] = []
                menu_dict[menu["parent_id"]]["children"].append(menu)

        return list(filter(lambda x: x["parent_id"] == 0, menu_list))


menu_controller = MenuController()
